﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Data;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace PlutoStudio
{
    /// <summary>
    /// 用于向开发人员暴露直接执行SQL语句的接口。
    /// </summary>
    [InheritedExport]
    public interface ISqlContext
    {
        /// <summary>
        /// 对数据库执行给定的 DDL/DML 命令。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="sql">命令字符串。</param>
        /// <param name="parameters">要应用于命令字符串的参数。</param>
        /// <returns>执行命令后由数据库返回的结果。</returns>
        int ExecuteSqlCommand(string sql, params object[] parameters);

        /// <summary>
        /// 对数据库执行给定的 DDL/DML 命令。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="transactionalBehavior">对于此命令控制事务的创建。</param>
        /// <param name="sql">命令字符串。</param>
        /// <param name="parameters">要应用于命令字符串的参数。</param>
        /// <returns>执行命令后由数据库返回的结果。</returns>
        int ExecuteSqlCommand(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters);

        /// <summary>
        /// 对数据库异步执行给定的 DDL/DML 命令。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="sql">命令字符串。</param>
        /// <param name="parameters">要应用于命令字符串的参数。</param>
        /// <returns>表示异步操作的任务。 任务结果包含执行命令后由数据库返回的结果。 </returns>
        Task<int> ExecuteSqlCommandAsync(string sql, params object[] parameters);

        /// <summary>
        /// 创建一个原始 SQL 查询，该查询将返回非给定类型的元素。 类型可以是包含与从查询返回的列名匹配的属性的任何类型，也可以是简单的基元类型。 该类型不必是实体类型。 即使返回对象的类型是实体类型，上下文也决不会跟踪此查询的结果。 使用 <see cref="SqlQuery(Type, string, object[])"/> 方法可返回上下文跟踪的实体。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.SqlQuery(typeof(Post), "SELECT * FROM dbo.Posts WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="sql">SQL 查询字符串。</param>
        /// <param name="parameters">要应用于 SQL 查询字符串的参数。 如果使用输出参数，则它们的值在完全读取结果之前不可用。 这是由于 <see cref="System.Data.Common.DbDataReader"/> 的基础行为而导致的，有关详细信息，请参见 http://go.microsoft.com/fwlink/?LinkID=398589。 </param>
        /// <returns>一个 <see cref="DbRawSqlQuery"/> 对象，此对象在枚举时将执行查询。</returns>
        DbRawSqlQuery SqlQuery(string sql, params object[] parameters);

        /// <summary>
        /// 对数据库异步执行给定的 DDL/DML 命令。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="transactionalBehavior">对于此命令控制事务的创建。</param>
        /// <param name="sql">命令字符串。</param>
        /// <param name="parameters">要应用于命令字符串的参数。</param>
        /// <returns>表示异步操作的任务。 任务结果包含执行命令后由数据库返回的结果。 </returns>
        Task<int> ExecuteSqlCommandAsync(TransactionalBehavior transactionalBehavior, string sql, params object[] parameters);

        /// <summary>
        /// 对数据库异步执行给定的 DDL/DML 命令。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="sql">命令字符串。</param>
        /// <param name="cancellationToken">等待任务完成期间要观察的 <see cref="CancellationToken"/>。</param>
        /// <param name="parameters">要应用于命令字符串的参数。</param>
        /// <returns>表示异步操作的任务。 任务结果包含执行命令后由数据库返回的结果。 </returns>
        Task<int> ExecuteSqlCommandAsync(string sql, CancellationToken cancellationToken, params object[] parameters);

        /// <summary>
        /// 对数据库异步执行给定的 DDL/DML 命令。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.ExecuteSqlCommand("UPDATE dbo.Posts SET Rating = 5 WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="transactionalBehavior">对于此命令控制事务的创建。</param>
        /// <param name="sql">命令字符串。</param>
        /// <param name="cancellationToken">等待任务完成期间要观察的 <see cref="CancellationToken"/>。</param>
        /// <param name="parameters">要应用于命令字符串的参数。</param>
        /// <returns>表示异步操作的任务。 任务结果包含执行命令后由数据库返回的结果。 </returns>
        Task<int> ExecuteSqlCommandAsync(TransactionalBehavior transactionalBehavior, string sql, CancellationToken cancellationToken, params object[] parameters);

        /// <summary>
        /// 创建一个原始 SQL 查询，该查询将返回给定类型的元素。 类型可以是包含与从查询返回的列名匹配的属性的任何类型，也可以是简单的基元类型。 该类型不必是实体类型。 即使返回对象的类型是实体类型，上下文也决不会跟踪此查询的结果。 使用 <see cref="SqlQuery(Type, string, object[])"/> 方法可返回上下文跟踪的实体。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.SqlQuery(typeof(Post), "SELECT * FROM dbo.Posts WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <param name="elementType">查询所返回对象的类型。</param>
        /// <param name="sql">SQL 查询字符串。</param>
        /// <param name="parameters">要应用于 SQL 查询字符串的参数。 如果使用输出参数，则它们的值在完全读取结果之前不可用。 这是由于 <see cref="System.Data.Common.DbDataReader"/> 的基础行为而导致的，有关详细信息，请参见 http://go.microsoft.com/fwlink/?LinkID=398589。 </param>
        /// <returns>一个 <see cref="DbRawSqlQuery"/> 对象，此对象在枚举时将执行查询。</returns>
        DbRawSqlQuery SqlQuery(Type elementType, string sql, params object[] parameters);

        /// <summary>
        /// 创建一个原始 SQL 查询，该查询将返回给定泛型类型的元素。 类型可以是包含与从查询返回的列名匹配的属性的任何类型，也可以是简单的基元类型。 该类型不必是实体类型。 即使返回对象的类型是实体类型，上下文也决不会跟踪此查询的结果。 使用 <see cref="SqlQuery(Type, string, object[])"/> 方法可返回上下文跟踪的实体。 与接受 SQL 的任何 API 一样，对任何用户输入进行参数化以便避免 SQL 注入攻击是十分重要的。 您可以在 SQL 查询字符串中包含参数占位符，然后将参数值作为附加参数提供。 您提供的任何参数值都将自动转换为 <see cref="DbParameter"/>。 context.Database.SqlQuery(typeof(Post), "SELECT * FROM dbo.Posts WHERE Author = @p0", userSuppliedAuthor); 或者，您还可以构造一个 <see cref="DbParameter"/> 并将它提供给 <see cref="SqlQuery(Type, string, object[])"/>。 这允许您在 SQL 查询字符串中使用命名参数。
        /// </summary>
        /// <typeparam name="TElement">查询所返回对象的类型。</typeparam>
        /// <param name="sql">SQL 查询字符串。</param>
        /// <param name="parameters">要应用于 SQL 查询字符串的参数。 如果使用输出参数，则它们的值在完全读取结果之前不可用。 这是由于 <see cref="System.Data.Common.DbDataReader"/> 的基础行为而导致的，有关详细信息，请参见 http://go.microsoft.com/fwlink/?LinkID=398589。 </param>
        /// <returns>一个 <see cref="DbRawSqlQuery"/> 对象，此对象在枚举时将执行查询。</returns>
        DbRawSqlQuery<TElement> SqlQuery<TElement>(string sql, params object[] parameters);

        /// <summary>
        /// 创建一个原始的<see cref="DbParameter"/>,该参数根据底层的数据库适配器生成相应的<see cref="DbParameter"/>。
        /// </summary>
        /// <param name="name">参数名称。</param>
        /// <param name="value">参数值。</param>
        /// <returns>一个 <see cref="DbParameter"/> 对象。</returns>
        DbParameter CreateParameter(string name, object value);

        /// <summary>
        /// 创建一组原始的<see cref="DbParameter"/>,该参数根据底层的数据库适配器生成相应的<see cref="DbParameter"/>。
        /// </summary>
        /// <param name="parameters">由参数组成的 <see cref="IDictionary{TKey, TValue}"/></param>
        /// <returns>一组 <see cref="DbParameter"/> 对象。</returns>
        IEnumerable<DbParameter> CreateParameters(IDictionary<string, object> parameters);

        /// <summary>
        /// 对基础存储连接开始一个事务。
        /// </summary>
        /// <returns>一个包装对基础存储的事务对象的访问的 <see cref="DbContextTransaction"/> 对象</returns>
        DbContextTransaction BeginTransaction();

        /// <summary>
        /// 使用指定的隔离级别对基础存储连接开始一个事务。
        /// </summary>
        /// <param name="isolationLevel">用于创建基础存储事务的数据库隔离级别</param>
        /// <returns>一个包装对基础存储的事务对象的访问的 <see cref="DbContextTransaction"/> 对象</returns>
        DbContextTransaction BeginTransaction(IsolationLevel isolationLevel);
    }
}
